﻿/*
  Copyright © Alexander G. Bykin, Russia 2009-2010
  This source is subject to the Microsoft Public License (Ms-PL).
  Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  All other rights reserved.
*/

namespace System.Windows.Controls
{
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Windows.Controls.Data;
    using System.Windows.Controls.Primitives;
    using System.Windows.Input;
    using System.Windows.Media.Imaging;

    /// <summary>
    /// Customizable DomainDataSource Group descriptors.
    /// </summary>
    /// <QualityBand>Stable</QualityBand>
    [TemplatePart(Name = "btnAddGroup", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnDeleteGroup", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnClearGroup", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnApply", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnCancel", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "dgcGroupPropertyPath", Type = typeof(DataGridColumn))]
    [TemplatePart(Name = "dgGroup", Type = typeof(DataGrid))]
    [TemplatePart(Name = "deleteRowCmd", Type = typeof(DynaCommand))]
    [TemplatePart(Name = "deleteRowToolTip", Type = typeof(DynaObject))]
    [TemplatePart(Name = "switchFieldsComboOrderByCmd", Type = typeof(DynaCommand))]
    [TemplatePart(Name = "switchFieldsComboOrderByToolTip", Type = typeof(DynaObject))]
    [TemplatePart(Name = "fieldsComboOrderByImage", Type = typeof(DynaObject))]
    public class DataGroup : Control
    {
        #region Constants

        /// <summary>
        /// The default order to use when there is no <see cref="DisplayAttribute.Order"/>
        /// value available for the property.
        /// </summary>
        /// <remarks>
        /// The value of 10000 is a standard default value, allowing
        /// some properties to be ordered at the beginning and some at the end.
        /// </remarks>
        private const int UnspecifiedOrder = 10000;

        private const string DATAGROUP_elementButtonAddGroup = "btnAddGroup";
        private const string DATAGROUP_elementButtonDeleteGroup = "btnDeleteGroup";
        private const string DATAGROUP_elementButtonClearGroup = "btnClearGroup";
        private const string DATAGROUP_elementButtonApply = "btnApply";
        private const string DATAGROUP_elementButtonCancel = "btnCancel";
        private const string DATAGROUP_elementDataGridColumnGroupPropertyPath = "dgcGroupPropertyPath";
        private const string DATAGROUP_elementDataGridColumnGroupPropertyPathHeader = "dgcGroupPropertyPathHeader";
        private const string DATAGROUP_elementDataGridGroup = "dgGroup";
        private const string DATAGROUP_elementDeleteRowCmd = "deleteRowCmd";
        private const string DATAGROUP_elementDeleteRowToolTip = "deleteRowToolTip";
        private const string DATAGROUP_elementSwitchFieldsComboOrderByCmd = "switchFieldsComboOrderByCmd";
        private const string DATAGROUP_elementSwitchFieldsComboOrderByToolTip = "switchFieldsComboOrderByToolTip";
        private const string DATAGROUP_elementFieldsComboOrderByImage = "fieldsComboOrderByImage";

        private const string DATAGROUP_DefaultButtonAddGroupTooltip = "Add Group";
        private const string DATAGROUP_DefaultButtonDeleteGroupTooltip = "Remove Group";
        private const string DATAGROUP_DefaultButtonClearGroupTooltip = "Clear Group";
        private const string DATAGROUP_DefaultButtonApplyContent = "Apply";
        private const string DATAGROUP_DefaultButtonCancelContent = "Cancel";
        private const string DATAGROUP_DefaultButtonApplyTooltip = "Apply filters";
        private const string DATAGROUP_DefaultButtonCancelTooltip = "Cancel filters";
        private const string DATAGROUP_DefaultDataGridColumnGroupPropertyPath = "Field name";
        private const string DATAGROUP_DefaultButtonSwitchFieldsComboOrderByTooltip = "Change 'Field name' combobox sort order";

        #endregion

        #region Dependency Properties

        #region DependencyProperty DomainEntityFieldCollection

        /// <summary>
        /// Identifies the DomainEntityFieldCollection dependency property.
        /// </summary>
        public static readonly DependencyProperty DomainEntityFieldCollectionProperty =
            DependencyProperty.Register(
                "DomainEntityFieldCollection",
                typeof(DomainEntityFieldCollection),
                typeof(DataGroup),
                new PropertyMetadata(new DomainEntityFieldCollection(), OnDomainEntityFieldCollectionPropertyChanged));

        /// <summary>
        /// DomainEntityFieldCollection property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its DomainEntityFieldCollection value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnDomainEntityFieldCollectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            //control.DomainEntityFieldCollection = e.NewValue as DomainEntityFieldCollection;
            control.RefreshListOfDomainEntityFields();
            control.RefreshGroupItems();
        }

        #endregion

        #region DependencyProperty ButtonAddGroupTooltip

        /// <summary>
        /// Identifies the ButtonAddGroupTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonAddGroupTooltipProperty =
            DependencyProperty.Register(
                "ButtonAddGroupTooltip",
                typeof(string),
                typeof(DataGroup),
                new PropertyMetadata(DATAGROUP_DefaultButtonAddGroupTooltip, OnButtonAddGroupTooltipPropertyChanged));

        /// <summary>
        /// ButtonAddGroupTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its ButtonAddGroupTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonAddGroupTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnAddGroup != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnAddGroup, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonDeleteGroupTooltip

        /// <summary>
        /// Identifies the ButtonDeleteGroupTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonDeleteGroupTooltipProperty =
            DependencyProperty.Register(
                "ButtonDeleteGroupTooltip",
                typeof(string),
                typeof(DataGroup),
                new PropertyMetadata(DATAGROUP_DefaultButtonDeleteGroupTooltip, OnButtonDeleteGroupTooltipPropertyChanged));

        /// <summary>
        /// ButtonDeleteGroupTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its ButtonDeleteGroupTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonDeleteGroupTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnDeleteGroup != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnDeleteGroup, newValue);
                if (control.dgGroup != null)
                  ((DynaObject)control.dgGroup.Resources[DATAGROUP_elementDeleteRowToolTip]).Value = newValue;
            }
        }

        #endregion

        #region DependencyProperty ButtonClearGroupTooltip

        /// <summary>
        /// Identifies the ButtonClearGroupTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonClearGroupTooltipProperty =
            DependencyProperty.Register(
                "ButtonClearGroupTooltip",
                typeof(string),
                typeof(DataGroup),
                new PropertyMetadata(DATAGROUP_DefaultButtonClearGroupTooltip, OnButtonClearGroupTooltipPropertyChanged));

        /// <summary>
        /// ButtonClearGroupTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its ButtonClearGroupTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonClearGroupTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnClearGroup != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnClearGroup, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonApplyContent

        /// <summary>
        /// Identifies the ButtonApplyContent dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonApplyContentProperty =
            DependencyProperty.Register(
                "ButtonApplyContent",
                typeof(string),
                typeof(DataGroup),
                new PropertyMetadata(DATAGROUP_DefaultButtonApplyContent, OnButtonApplyContentPropertyChanged));

        /// <summary>
        /// ButtonApplyContent property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its ButtonApplyContent value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonApplyContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnApply != null &&
                !string.IsNullOrEmpty(newValue))
            {
                control.btnApply.Content = newValue;
            }
        }

        #endregion

        #region DependencyProperty ButtonCancelContent

        /// <summary>
        /// Identifies the ButtonCancelContent dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonCancelContentProperty =
            DependencyProperty.Register(
                "ButtonCancelContent",
                typeof(string),
                typeof(DataGroup),
                new PropertyMetadata(DATAGROUP_DefaultButtonCancelContent, OnButtonCancelContentPropertyChanged));

        /// <summary>
        /// ButtonCancelContent property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its ButtonCancelContent value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonCancelContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnCancel != null &&
                !string.IsNullOrEmpty(newValue))
            {
                control.btnCancel.Content = newValue;
            }
        }

        #endregion

        #region DependencyProperty ButtonApplyTooltip

        /// <summary>
        /// Identifies the ButtonApplyTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonApplyTooltipProperty =
            DependencyProperty.Register(
                "ButtonApplyTooltip",
                typeof(string),
                typeof(DataGroup),
                new PropertyMetadata(DATAGROUP_DefaultButtonApplyTooltip, OnButtonApplyTooltipPropertyChanged));

        /// <summary>
        /// ButtonApplyTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its ButtonApplyTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonApplyTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnApply != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnApply, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonCancelTooltip

        /// <summary>
        /// Identifies the ButtonCancelTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonCancelTooltipProperty =
            DependencyProperty.Register(
                "ButtonCancelTooltip",
                typeof(string),
                typeof(DataGroup),
                new PropertyMetadata(DATAGROUP_DefaultButtonCancelTooltip, OnButtonCancelTooltipPropertyChanged));

        /// <summary>
        /// ButtonCancelTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its ButtonCancelTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonCancelTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnCancel != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnCancel, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonSwitchFieldsComboOrderByTooltip

        /// <summary>
        /// Identifies the ButtonSwitchFieldsComboOrderByTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonSwitchFieldsComboOrderByTooltipProperty =
            DependencyProperty.Register(
                "ButtonSwitchFieldsComboOrderByTooltip",
                typeof(string),
                typeof(DataGroup),
                new PropertyMetadata(DATAGROUP_DefaultButtonSwitchFieldsComboOrderByTooltip, OnButtonSwitchFieldsComboOrderByTooltipPropertyChanged));

        /// <summary>
        /// ButtonSwitchFieldsComboOrderByTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its ButtonSwitchFieldsComboOrderByTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonSwitchFieldsComboOrderByTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          DataGroup control = d as DataGroup;
          if (control == null) return;

          string newValue = e.NewValue as string;

          if (control.dgGroup != null && !string.IsNullOrEmpty(newValue))
            ((DynaObject)control.dgGroup.Resources[DATAGROUP_elementSwitchFieldsComboOrderByToolTip]).Value = newValue;
        }

        #endregion

        #region DependencyProperty DomainDataSource

        /// <summary>
        /// Identifies the DomainDataSource dependency property.
        /// </summary>
        public static readonly DependencyProperty DomainDataSourceProperty =
            DependencyProperty.Register(
                "DomainDataSource",
                typeof(DomainDataSource),
                typeof(DataGroup),
                new PropertyMetadata(OnDomainDataSourcePropertyChanged));

        /// <summary>
        /// DomainDataSource property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its DomainDataSource value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnDomainDataSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            if (e.OldValue != null) {
              var old = e.OldValue as DomainDataSource;
              if (old != null)
                old.FilterDescriptors.CollectionChanged -= control.GroupDescriptorsChanged;
            }
            control.RefreshGroupItems();
            if (control.DomainDataSource != null)
              control.DomainDataSource.GroupDescriptors.CollectionChanged += control.GroupDescriptorsChanged;
        }

        void RefreshGroupItems()
        {
          DomainDataSource.GetDDSGroupDescriptorsCopy(DomainEntityFieldCollection.ToList(), dataGridGroupItems);
          RefreshControls();
        }

        void GroupDescriptorsChanged(object sender, Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
          // DomainDataSource.GroupDescriptors are changed by external control
          if (!changingGroupDescrs && ListenGroupDescriptorsChanges)
            RefreshGroupItems();
        }

        #endregion

        #region DependencyProperty ListenGroupDescriptorsChangesProperty

        /// <summary>
        /// Identifies the ListenGroupDescriptorsChangesProperty dependency property.
        /// </summary>
        public static readonly DependencyProperty ListenGroupDescriptorsChangesProperty =
            DependencyProperty.Register(
                "ListenGroupDescriptorsChangesProperty",
                typeof(bool),
                typeof(DataGroup),
                new PropertyMetadata(false/*defaultValue*/, OnListenGroupDescriptorsChangesPropertyChanged));

        /// <summary>
        /// ListenGroupDescriptorsChangesProperty changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its ListenFilterDescriptorsChangesProperty value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnListenGroupDescriptorsChangesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          DataGroup control = d as DataGroup;
          if (control == null) {
            return;
          }
          if (e.NewValue != null) { }
        }

        #endregion

        #region DependencyProperty GroupPropertyPathHeader

        /// <summary>
        /// Identifies the GroupPropertyPathHeader dependency property.
        /// </summary>
        public static readonly DependencyProperty GroupPropertyPathHeaderProperty =
            DependencyProperty.Register(
                "GroupPropertyPathHeader",
                typeof(string),
                typeof(DataGroup),
                new PropertyMetadata(DATAGROUP_DefaultDataGridColumnGroupPropertyPath, OnGroupPropertyPathHeaderPropertyChanged));

        /// <summary>
        /// GroupPropertyPathHeader property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its GroupPropertyPathHeader value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnGroupPropertyPathHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.dgGroup != null &&
                !string.IsNullOrEmpty(newValue))
            {
              ((DynaString)control.dgGroup.Resources[DATAGROUP_elementDataGridColumnGroupPropertyPathHeader]).Value = newValue;
            }
        }

        #endregion

        #region DependencyProperty ExcludeFieldList

        /// <summary>
        /// Identifies the ExcludeFieldList dependency property.
        /// </summary>
        public static readonly DependencyProperty ExcludeFieldListProperty =
            DependencyProperty.Register(
            "ExcludeFieldList",
            typeof(string),
            typeof(DataGroup),
            new PropertyMetadata(string.Empty, OnExcludeFieldListPropertyChanged));

        /// <summary>
        /// ExcludeFieldList property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its ExcludeFieldList value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnExcludeFieldListPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            //control.ExcludeFieldList = (e.NewValue as string);
        }

        #endregion

        #region DependencyProperty IncludeFieldList

        /// <summary>
        /// Identifies the IncludeFieldList dependency property.
        /// </summary>
        public static readonly DependencyProperty IncludeFieldListProperty =
            DependencyProperty.Register(
            "IncludeFieldList",
            typeof(string),
            typeof(DataGroup),
            new PropertyMetadata(string.Empty, OnIncludeFieldListPropertyChanged));

        /// <summary>
        /// IncludeFieldList property changed handler.
        /// </summary>
        /// <param name="d">DataGroup that changed its IncludeFieldList value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnIncludeFieldListPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGroup control = d as DataGroup;
            if (control == null)
            {
                return;
            }

            //control.IncludeFieldList = (e.NewValue as string);
        }

        #endregion

        #region DependencyProperty EntityFieldsComboOrderBy

        public static readonly DependencyProperty EntityFieldsComboOrderByProperty =
            DependencyProperty.Register(
            "EntityFieldsComboOrderBy",
            typeof(EntityFieldsOrder),
            typeof(DataGroup),
            new PropertyMetadata(EntityFieldsOrder.Alphabetical, OnEntityFieldsComboOrderByPropertyChanged));

        public EntityFieldsOrder EntityFieldsComboOrderBy
        {
          get { return (EntityFieldsOrder)GetValue(EntityFieldsComboOrderByProperty); }
          set { SetValue(EntityFieldsComboOrderByProperty, value); }
        }

        private static void OnEntityFieldsComboOrderByPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          DataGroup control = d as DataGroup;
          if (control == null) return;
          control.SetFieldsComboOrderByImage();
          control.RefreshListOfDomainEntityFields();
        }

        private void SetFieldsComboOrderByImage()
        {
          switch (EntityFieldsComboOrderBy) {
            case EntityFieldsOrder.Alphabetical:
              var img = new BitmapImage(new Uri(@"/System.Windows.Controls.Data.RIADataFilter.Control;component/Images/Alphabet.png", UriKind.Relative));
              ((DynaObject)this.dgGroup.Resources[DATAGROUP_elementFieldsComboOrderByImage]).Value = img;
              break;
            case EntityFieldsOrder.DisplayOrder:
              img = new BitmapImage(new Uri(@"/System.Windows.Controls.Data.RIADataFilter.Control;component/Images/Numbering.png", UriKind.Relative));
              ((DynaObject)this.dgGroup.Resources[DATAGROUP_elementFieldsComboOrderByImage]).Value = img;
              break;
          }
        }

        #endregion

        #endregion

        #region Private Properties

        #region Private Property dataGridGroupItems

        private List<DataGridGroupItem> dataGridGroupItems { get; set; }

        #endregion

        #region Private Property btnAddGroup

        /// <summary>
        /// Private accessor to btnAddGroup Button.
        /// </summary>
        private ButtonBase btnAddGroup { get; set; }

        #endregion

        #region Private Property btnDeleteGroup

        /// <summary>
        /// Private accessor to btnDeleteGroup Button.
        /// </summary>
        private ButtonBase btnDeleteGroup { get; set; }
        private ICommand deleteCmd { get; set; }

        #endregion

        #region Private Property btnClearGroup

        /// <summary>
        /// Private accessor to btnClearGroup Button.
        /// </summary>
        private ButtonBase btnClearGroup { get; set; }
        private ICommand clearCmd { get; set; }

        #endregion

        #region Private Property btnApply

        /// <summary>
        /// Private accessor to btnApply Button.
        /// </summary>
        private ButtonBase btnApply { get; set; }
        private ICommand applyCmd { get; set; }

        #endregion

        #region Private Property btnCancel

        /// <summary>
        /// Private accessor to btnCancel Button.
        /// </summary>
        private ButtonBase btnCancel { get; set; }
        private ICommand cancelCmd { get; set; }

        #endregion

        #region Private Property dgGroup

        /// <summary>
        /// Private accessor to dgGroup DataGrid.
        /// </summary>
        private DataGrid dgGroup { get; set; }

        #endregion

        #region Private Property dgcGroupPropertyPath

        /// <summary>
        /// Private accessor to dgcGroupPropertyPath DataGrid Column.
        /// </summary>
        private DataGridColumn dgcGroupPropertyPath { get; set; }

        #endregion

        #region Private Property deleteRowCmd

        private ICommand deleteRowCmd { get; set; }

        #endregion

        #region Private Property switchFieldsComboOrderByCmd

        private ICommand switchFieldsComboOrderByCmd { get; set; }

        #endregion

        #endregion

        #region Public Properties

        #region Public Property DomainEntityFieldCollection

        public DomainEntityFieldCollection DomainEntityFieldCollection
        {
            get
            {
                return GetValue(DomainEntityFieldCollectionProperty) as DomainEntityFieldCollection;
            }
            set
            {
                SetValue(DomainEntityFieldCollectionProperty, value);
            }
        }

        #endregion

        #region Public Property ListOfDomainEntityFields

        /// <summary>
        /// Gets the list of DomainEntityField.
        /// </summary>
        public List<DomainEntityField> ListOfDomainEntityFields { get; private set; }

        #endregion

        #region Public Property ButtonAddGroupTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the AddGroup Button.
        /// </summary>
        public string ButtonAddGroupTooltip
        {
            get
            {
                return this.GetValue(ButtonAddGroupTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonAddGroupTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonDeleteGroupTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the DeleteGroup Button.
        /// </summary>
        public string ButtonDeleteGroupTooltip
        {
            get
            {
                return this.GetValue(ButtonDeleteGroupTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonDeleteGroupTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonClearGroupTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the ClearGroup Button.
        /// </summary>
        public string ButtonClearGroupTooltip
        {
            get
            {
                return this.GetValue(ButtonClearGroupTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonClearGroupTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonApplyTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the Apply Button.
        /// </summary>
        public string ButtonApplyTooltip
        {
            get
            {
                return this.GetValue(ButtonApplyTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonApplyTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonCancelTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the Cancel Button.
        /// </summary>
        public string ButtonCancelTooltip
        {
            get
            {
                return this.GetValue(ButtonCancelTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonCancelTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Property ButtonSwitchFieldsComboOrderByTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the SwitchFieldsComboOrderBy Button.
        /// </summary>
        public string ButtonSwitchFieldsComboOrderByTooltip
        {
          get
          {
            return this.GetValue(ButtonSwitchFieldsComboOrderByTooltipProperty) as string;
          }

          set
          {
            if (!string.IsNullOrEmpty(value))
            {
              this.SetValue(ButtonSwitchFieldsComboOrderByTooltipProperty, value);
            }
          }
        }

        #endregion

        #region Public Property ButtonApplyContent

        /// <summary>
        /// Gets or sets the Content of the Apply Button.
        /// </summary>
        public string ButtonApplyContent
        {
            get
            {
                return this.GetValue(ButtonApplyContentProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonApplyContentProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonCancelContent

        /// <summary>
        /// Gets or sets the Content of the Cancel button.
        /// </summary>
        public string ButtonCancelContent
        {
            get
            {
                return this.GetValue(ButtonCancelContentProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonCancelContentProperty, value);
                }
            }
        }

        #endregion

        #region Public Property DomainDataSource

        /// <summary>
        /// Gets or sets a DomainDataSource.
        /// </summary>
        public DomainDataSource DomainDataSource
        {
            get
            {
                return this.GetValue(DomainDataSourceProperty) as DomainDataSource;
            }
            set
            {
                this.SetValue(DomainDataSourceProperty, value);
            }
        }

        #endregion

        #region Public Property ListenGroupDescriptorsChanges

        [DefaultValue(false)]
        public bool ListenGroupDescriptorsChanges
        {
          get { return (bool)this.GetValue(ListenGroupDescriptorsChangesProperty); }
          set { this.SetValue(ListenGroupDescriptorsChangesProperty, value); }
        }

        #endregion

        #region Public Property GroupPropertyPathHeader

        /// <summary>
        /// Gets or sets the Header of the GroupPropertyPath.
        /// </summary>
        public string GroupPropertyPathHeader
        {
            get
            {
                return this.GetValue(GroupPropertyPathHeaderProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(GroupPropertyPathHeaderProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ExcludeFieldList

        /// <summary>
        /// Gets or Sets the Field list than must be Ignored when filling field list for ComboBox
        /// </summary>
        public string ExcludeFieldList
        {
            get
            {
                return (string)GetValue(ExcludeFieldListProperty);
            }
            set
            {
                SetValue(ExcludeFieldListProperty, value);
            }
        }

        #endregion

        #region Public Property IncludeFieldList

        /// <summary>
        /// Gets or Sets the Field list than must be Added when filling field list for ComboBox
        /// </summary>
        public string IncludeFieldList
        {
            get
            {
                return (string)GetValue(IncludeFieldListProperty);
            }
            set
            {
                SetValue(IncludeFieldListProperty, value);
            }
        }

        #endregion

        #region Public Property OnApplyButtonBeforeClick

        public event EventHandler OnApplyButtonBeforeClick;

        #endregion

        #region Public Property OnCancelButtonBeforeClick

        public event EventHandler OnCancelButtonBeforeClick;

        #endregion

        #region Public Property OnApplyButtonAfterClick

        public event EventHandler OnApplyButtonAfterClick;

        #endregion

        #region Public Property OnCancelButtonAfterClick

        public event EventHandler OnCancelButtonAfterClick;

        #endregion

        #region Public Property OnCanCancel

        public event CanCancelEventHandler OnCanCancel;

        #endregion

        #region Public Property CellEditorPrepared

        public event EventHandler CellEditorPrepared;

        #endregion

        #endregion

        #region Constructors

        public DataGroup()
        {
            DefaultStyleKey = typeof(DataGroup);
            this.dataGridGroupItems = new List<DataGridGroupItem>();
            this.LayoutUpdated += OnDataGroupLayoutUpdated;
            applyCmd  = new DelegateCommand<object>(ApplyFilters , CanApplyFilters );
            cancelCmd = new DelegateCommand<object>(CancelFilters, CanCancelFilters);
            deleteCmd = new DelegateCommand<object>(DeleteGroupItem, CanDeleteGroupItem);
            clearCmd  = new DelegateCommand<object>(ClearGroupItem, CanClearGroupItem);
            deleteRowCmd = new DelegateCommand<object>(AsyncDeleteRowGroupItem, CanDeleteRowGroupItem);
            switchFieldsComboOrderByCmd = new DelegateCommand<object>(SwitchFieldsComboOrderBy, CanSwitchFieldsComboOrderBy);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            #region Button AddGroup

            if (this.btnAddGroup != null)
            {
                this.btnAddGroup.Click -= new RoutedEventHandler(this.OnButtonAddGroupClick);
            }

            this.btnAddGroup = GetTemplateChild(DATAGROUP_elementButtonAddGroup) as ButtonBase;

            if (this.btnAddGroup != null)
            {
                this.btnAddGroup.Click += new RoutedEventHandler(this.OnButtonAddGroupClick);

                ToolTipService.SetToolTip(this.btnAddGroup, this.ButtonAddGroupTooltip);

                /*if (this.AddGroupButtonStyle != null)
                {
                    this._addGroupButton.SetBinding(ButtonBase.StyleProperty, new Binding("AddGroupButtonStyle") { Source = this });
                }*/
            }

            #endregion

            #region Button DeleteGroup

            if (this.btnDeleteGroup != null)
            {
                this.btnDeleteGroup.Command = null;
            }

            this.btnDeleteGroup = GetTemplateChild(DATAGROUP_elementButtonDeleteGroup) as ButtonBase;

            if (this.btnDeleteGroup != null)
            {
                this.btnDeleteGroup.Command = deleteCmd;

                ToolTipService.SetToolTip(this.btnDeleteGroup, this.ButtonDeleteGroupTooltip);

                /*if (this.DeleteGroupButtonStyle != null)
                {
                    this._deleteGroupButton.SetBinding(ButtonBase.StyleProperty, new Binding("DeleteGroupButtonStyle") { Source = this });
                }*/
            }

            #endregion

            #region Button ClearGroup

            if (this.btnClearGroup != null)
            {
                this.btnClearGroup.Command = null;
            }

            this.btnClearGroup = GetTemplateChild(DATAGROUP_elementButtonClearGroup) as ButtonBase;

            if (this.btnClearGroup != null)
            {
                this.btnClearGroup.Command = clearCmd;

                ToolTipService.SetToolTip(this.btnClearGroup, this.ButtonClearGroupTooltip);

                /*if (this.ClearGroupButtonStyle != null)
                {
                    this._clearGroupButton.SetBinding(ButtonBase.StyleProperty, new Binding("ClearGroupButtonStyle") { Source = this });
                }*/
            }

            #endregion

            #region Button Apply

            if (this.btnApply != null)
            {
                this.btnApply.Command = null;
            }

            this.btnApply = GetTemplateChild(DATAGROUP_elementButtonApply) as ButtonBase;

            if (this.btnApply != null)
            {
                this.btnApply.Command = applyCmd;
                this.btnApply.Content = this.ButtonApplyContent;

                ToolTipService.SetToolTip(this.btnApply, this.ButtonApplyTooltip);

                /*if (this.AddRecordButtonStyle != null)
                                {
                                    this._addRecordButton.SetBinding(ButtonBase.StyleProperty, new Binding("CancelButtonStyle") { Source = this });
                                }*/
            }

            #endregion

            #region Button Cancel

            if (this.btnCancel != null)
            {
                this.btnCancel.Command = null;
            }

            this.btnCancel = GetTemplateChild(DATAGROUP_elementButtonCancel) as ButtonBase;

            if (this.btnCancel != null)
            {
                this.btnCancel.Command = cancelCmd;
                this.btnCancel.Content = this.ButtonCancelContent;

                ToolTipService.SetToolTip(this.btnCancel, this.ButtonCancelTooltip);

                /*if (this.AddRecordButtonStyle != null)
                                {
                                    this._addRecordButton.SetBinding(ButtonBase.StyleProperty, new Binding("CancelButtonStyle") { Source = this });
                                }*/
            }

            #endregion

            #region DataGridColumn GroupPropertyPath

            this.dgcGroupPropertyPath = GetTemplateChild(DATAGROUP_elementDataGridColumnGroupPropertyPath) as DataGridColumn;

            if (this.dgcGroupPropertyPath != null) { }

            #endregion

            #region DataGrid Group

            if (this.dgGroup != null)
            {
                this.dgGroup.PreparingCellForEdit -= OnDataGridGroupPreparingCellForEdit;
                this.dgGroup.SelectionChanged     -= dgGroup_SelectionChanged;
                this.dgGroup.CurrentCellChanged   -= dgGroup_CurrentCellChanged;
                ((DynaCommand)this.dgGroup.Resources[DATAGROUP_elementDeleteRowCmd]).Value = null;
                ((DynaObject )this.dgGroup.Resources[DATAGROUP_elementDeleteRowToolTip]).Value = null;
                ((DynaCommand)this.dgGroup.Resources[DATAGROUP_elementSwitchFieldsComboOrderByCmd]).Value = null;
                ((DynaObject )this.dgGroup.Resources[DATAGROUP_elementSwitchFieldsComboOrderByToolTip]).Value = null;
                ((DynaObject )this.dgGroup.Resources[DATAGROUP_elementFieldsComboOrderByImage]).Value = null;
                ((DynaString )this.dgGroup.Resources[DATAGROUP_elementDataGridColumnGroupPropertyPathHeader]).Value = null;
            }

            this.dgGroup = GetTemplateChild(DATAGROUP_elementDataGridGroup) as DataGrid;

            if (this.dgGroup != null)
            {
                this.dgGroup.DataGridRefreshItemsSource(this.dataGridGroupItems);
                this.dgGroup.PreparingCellForEdit += OnDataGridGroupPreparingCellForEdit;
                this.dgGroup.SelectionChanged     += dgGroup_SelectionChanged;
                this.dgGroup.CurrentCellChanged   += dgGroup_CurrentCellChanged;
                ((DynaCommand)this.dgGroup.Resources[DATAGROUP_elementDeleteRowCmd]).Value = deleteRowCmd;
                ((DynaObject )this.dgGroup.Resources[DATAGROUP_elementDeleteRowToolTip]).Value = this.ButtonDeleteGroupTooltip;
                ((DynaCommand)this.dgGroup.Resources[DATAGROUP_elementSwitchFieldsComboOrderByCmd]).Value = switchFieldsComboOrderByCmd;
                ((DynaObject )this.dgGroup.Resources[DATAGROUP_elementSwitchFieldsComboOrderByToolTip]).Value = this.ButtonSwitchFieldsComboOrderByTooltip;
                SetFieldsComboOrderByImage();
                ((DynaString)this.dgGroup.Resources[DATAGROUP_elementDataGridColumnGroupPropertyPathHeader]).Value = this.GroupPropertyPathHeader;
            }

            #endregion
        }

        void dgGroup_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
          deleteCmd.CanExecute(null);
          deleteRowCmd.CanExecute(null);
        }

        void dgGroup_CurrentCellChanged(object sender, EventArgs e)
        {
          dgGroup.BeginEdit();
        }

        #endregion

        #region Private Methods

        #region Private Method RefreshListOfDomainEntityFields

        private void RefreshListOfDomainEntityFields()
        {
          if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) && this.DomainDataSource != null)
          {
            var fields = Utilities.GetListOfDomainEntityFields(this.DomainDataSource, Utilities.ParseStringAsListOfString(this.IncludeFieldList), Utilities.ParseStringAsListOfString(this.ExcludeFieldList), this.DomainEntityFieldCollection);
            switch (EntityFieldsComboOrderBy) {
              case EntityFieldsOrder.Alphabetical: fields = fields.OrderBy(r => r.DisplayName).ToList(); break;
              case EntityFieldsOrder.DisplayOrder: fields = fields.OrderBy(r => r.OrderId    ).ToList(); break;
            }
            this.ListOfDomainEntityFields = fields;
          }
        }

        #endregion

        #region Private Method OnDataGroupLayoutUpdated

        private void OnDataGroupLayoutUpdated(object sender, EventArgs e)
        {
          if (this.ListOfDomainEntityFields == null)
            RefreshListOfDomainEntityFields();
        }

        #endregion

        #region Private Method RefreshCommands

        private void RefreshCommands()
        {
          this.applyCmd.CanExecute(null);
          this.cancelCmd.CanExecute(null);
          this.deleteCmd.CanExecute(null);
          this.clearCmd.CanExecute(null);
          this.deleteRowCmd.CanExecute(null);
        }

        #endregion

        #region Private Method RefreshControls

        private void RefreshControls()
        {
          this.dgGroup.DataGridRefreshItemsSource(this.dataGridGroupItems);
          RefreshCommands();
        }

        #endregion

        #region Private Method OnButtonAddGroupClick

        /// <summary>
        /// Handles the click of the AddGroup button.
        /// </summary>
        /// <param name="sender">The button.</param>
        /// <param name="e">The event args.</param>
        private void OnButtonAddGroupClick(object sender, RoutedEventArgs e)
        {
            this.AddGroupItem();
        }

        #endregion

        #region Private Method OnDataGridGroupPreparingCellForEdit

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">DataGridPreparingCellForEditEventArgs</param>
        private void OnDataGridGroupPreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
        {
            DataGridGroupItem dgSelectedItem = (this.dgGroup.SelectedItem as DataGridGroupItem);
            FrameworkElement editingElement = e.EditingElement;

            if (editingElement == null)
            {
                return;
            }

            string columnName = e.Column.GetValue(FrameworkElement.NameProperty) as string;

            if (string.IsNullOrWhiteSpace(columnName))
            {
                return;
            }

            bool processed = false;
            switch (columnName)
            {
                //Initialized dgcGroupPropertyPath DataGridTemplateColumn.CellEditingTemplate
                case DATAGROUP_elementDataGridColumnGroupPropertyPath:
                    if (e.EditingElement.GetType() == typeof(ComboBox))
                    {
                        ComboBox element = e.EditingElement as ComboBox;

                        if (element == null)
                        {
                            return;
                        }

                        element.SelectionChanged -= OnGroupPropertyPathComboBoxSelectionChanged;
                        element.DisplayMemberPath = "DisplayName";
                        element.ItemsSource = this.ListOfDomainEntityFields;
                        if (this.dgGroup.SelectedItem != null)
                        {
                            element.SelectedItem = this.ListOfDomainEntityFields.FirstOrDefault(r => r.PropertyPath == dgSelectedItem.GroupDescriptor.PropertyPath);
                        }
                        element.SelectionChanged += OnGroupPropertyPathComboBoxSelectionChanged;
                        processed = true;
                    }
                    break;
            }
            if (!processed) {
              if (editingElement is TextBox) {
                (editingElement as TextBox).TextChanged -= DataGridGroup_CellTextChanged;
                (editingElement as TextBox).TextChanged += DataGridGroup_CellTextChanged;
                processCellChanges(editingElement);
              }
              else if (editingElement is CheckBox) {
                (editingElement as CheckBox).Click -= DataGridGroup_CellCheckBoxClick;
                (editingElement as CheckBox).Click += DataGridGroup_CellCheckBoxClick;
                processCellChanges(editingElement);
              }
            }

            if (CellEditorPrepared != null)
              CellEditorPrepared(editingElement, null);
        }

        void processCellChanges(object ed)
        {
          if (ed is CheckBox) {
            var be = (ed as CheckBox).GetBindingExpression(CheckBox.IsCheckedProperty);
            if (be != null) be.UpdateSource();
            RefreshCommands();
          }
          else if (ed is TextBox) {
            var be = (ed as TextBox).GetBindingExpression(TextBox.TextProperty);
            if (be != null) be.UpdateSource();
            RefreshCommands();
          }
        }

        void DataGridGroup_CellCheckBoxClick(object sender, RoutedEventArgs e)
        {
          processCellChanges(sender);
        }

        void DataGridGroup_CellTextChanged(object sender, TextChangedEventArgs e)
        {
          processCellChanges(sender);
        }

        #endregion

        #region Private Method OnGroupPropertyPathComboBoxSelectionChanged

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">SelectionChangedEventArgs</param>
        private void OnGroupPropertyPathComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            DomainEntityField result = ((ComboBox)sender).SelectedItem as DomainEntityField;

            if (this.dataGridGroupItems == null ||
                this.dataGridGroupItems.Count == 0 ||
                this.dgGroup.SelectedItem == null ||
                result == null)
            {
                return;
            }

            DataGridGroupItem record = (this.dgGroup.SelectedItem as DataGridGroupItem);
            record.GroupDescriptor.PropertyPath = result.PropertyPath;
            RefreshCommands();
        }

        #endregion

        #region Private Method AddGroupItem

        /// <summary>
        /// Add Control.GroupDesctiptors
        /// </summary>
        /// <returns></returns>
        private bool AddGroupItem()
        {
            if (this.dataGridGroupItems == null ||
                this.ListOfDomainEntityFields == null ||
                this.ListOfDomainEntityFields.Count == 0)
            {
                return false;
            }

            this.dataGridGroupItems.Add(
                new DataGridGroupItem(this.ListOfDomainEntityFields)
                {
                    GroupDescriptor = new GroupDescriptor(this.ListOfDomainEntityFields[0].PropertyPath)
                });
            this.RefreshControls();

            return true;
        }

        #endregion

        #region Private Method DeleteGroupItem

        /// <summary>
        /// Removes selected items from dataGridGroupItems
        /// </summary>
        /// <returns></returns>
        private void DeleteGroupItem(object param = null)
        {
            if (this.dataGridGroupItems == null ||
                this.dataGridGroupItems.Count == 0 ||
                this.dgGroup.SelectedItem == null)
            {
                return;
            }

            if (dgGroup.SelectedItems.Count > 1) {
              var lst = new List<object>();
              foreach (var i in dgGroup.SelectedItems) lst.Add(i);
              foreach (var j in lst) this.dataGridGroupItems.Remove((DataGridGroupItem)j);
            }
            else this.dataGridGroupItems.Remove((DataGridGroupItem)this.dgGroup.SelectedItem);

            this.RefreshControls();
        }

        private bool CanDeleteGroupItem(object param)
        {
          return this.dataGridGroupItems != null && this.dataGridGroupItems.Count > 0 &&
                 this.dgGroup != null && this.dgGroup.SelectedItem != null;
        }

        #endregion

        #region Private Method DeleteRowGroupItem

        /// <summary>
        /// Removes selected item from dataGridGroupItems
        /// </summary>
        /// <returns></returns>
        private void DeleteRowGroupItem(object param = null)
        {
          if (this.dataGridGroupItems == null ||
              this.dataGridGroupItems.Count == 0 ||
              this.dgGroup.SelectedItem == null || dgGroup.SelectedItems.Count != 1)
          {
            return;
          }

          this.dataGridGroupItems.Remove((DataGridGroupItem)this.dgGroup.SelectedItem);
          this.RefreshControls();
        }

        private void AsyncDeleteRowGroupItem(object param)
        {
          // in grid DeleteRowBtn defines ClickMode="Press", that's why we cannot delete right away, UI is not "stable" yet and must finish its work
          // also SelectedItem won't be changed as it happens in ClickMode="Release", so we must do it manually

          DataGridGroupItem rowItem = null;
          if (param is FrameworkElement && ((FrameworkElement)param).DataContext is DataGridGroupItem)
            rowItem = ((FrameworkElement)param).DataContext as DataGridGroupItem;

          this.Dispatcher.BeginInvoke(delegate {
            if (rowItem != null) dgGroup.SelectedItem = rowItem;
            DeleteRowGroupItem(param);
          });
        }

        private bool CanDeleteRowGroupItem(object param)
        {
          return this.dataGridGroupItems != null && this.dataGridGroupItems.Count > 0 &&
                 this.dgGroup != null && this.dgGroup.SelectedItem != null && dgGroup.SelectedItems.Count == 1;
        }

        #endregion

        #region Private Method ClearGroupItem

        /// <summary>
        /// Clear Control.GroupDesctiptors
        /// </summary>
        /// <returns></returns>
        private void ClearGroupItem(object param = null)
        {
            if (this.dataGridGroupItems == null ||
                this.dataGridGroupItems.Count == 0)
            {
                return;
            }

            while (this.dataGridGroupItems.Count > 0)
            {
                this.dataGridGroupItems.RemoveAt(0);
            }

            this.RefreshControls();
        }

        private bool CanClearGroupItem(object param)
        {
          return this.dataGridGroupItems != null && this.dataGridGroupItems.Count > 0;
        }

        #endregion

        #region Private Method SwitchFieldsComboOrderBy

        /// <summary>
        /// Delete selected filter item from list.
        /// </summary>
        private void SwitchFieldsComboOrderBy(object param)
        {
          switch (EntityFieldsComboOrderBy) {
            case EntityFieldsOrder.Alphabetical:
              dgGroup.CommitEdit();
              EntityFieldsComboOrderBy = EntityFieldsOrder.DisplayOrder;
              break;
            case EntityFieldsOrder.DisplayOrder:
              dgGroup.CommitEdit();
              EntityFieldsComboOrderBy = EntityFieldsOrder.Alphabetical;
              break;
          }
        }

        private bool CanSwitchFieldsComboOrderBy(object param)
        {
          return (EntityFieldsComboOrderBy == EntityFieldsOrder.Alphabetical ||
                  EntityFieldsComboOrderBy == EntityFieldsOrder.DisplayOrder);
        }

        #endregion

        #endregion

        #region Public Methods

        #region Private Method ApplyFilters

        /// <summary>
        /// Apply and add group intems to the DomainDataSource.
        /// </summary>
        public void ApplyFilters(object param = null)
        {
            if (this.OnApplyButtonBeforeClick != null)
            {
                this.OnApplyButtonBeforeClick(this, null);
            }

            if (this.DomainDataSource != null)
            {
              changingGroupDescrs = true;
              try {
                this.DomainDataSource.IsEnabled = false;
                this.DomainDataSource.SetToDDSGroupDescriptorsCopy(this.dataGridGroupItems);
                this.DomainDataSource.IsEnabled = true;
              }
              finally {
                changingGroupDescrs = false;
              };
            }

            if (this.OnApplyButtonAfterClick != null)
            {
                this.OnApplyButtonAfterClick(this, null);
                // rereading from the current state of dds (in case GroupDescriptors were postprocessed by OnApplyButtonAfterClick)
                if (this.DomainDataSource != null && !ListenGroupDescriptorsChanges)
                {
                  this.DomainDataSource.IsEnabled = false;
                  this.DomainDataSource.GetDDSGroupDescriptorsCopy(this.ListOfDomainEntityFields, this.dataGridGroupItems);
                  this.DomainDataSource.IsEnabled = true;
                  RefreshControls();
                  return;
                }
            }

            if (this.DomainDataSource != null) {
              this.applyCmd.CanExecute(null);
              this.cancelCmd.CanExecute(null);
            }
        }

        public bool CanApplyFilters(object param)
        {
          if (this.DomainDataSource != null)
            return !this.DomainDataSource.DDSGroupDescriptorsEqual(this.dataGridGroupItems);
          else
            return false;
        }

        private bool changingGroupDescrs = false;

        #endregion

        #region Private Method CancelFilters

        /// <summary>
        /// Cancel add group intems to the DomainDataSource.
        /// </summary>
        public void CancelFilters(object param = null)
        {
            if (this.OnCancelButtonBeforeClick != null)
            {
                this.OnCancelButtonBeforeClick(this, null);
            }

            if (this.DomainDataSource != null)
            {
                this.DomainDataSource.IsEnabled = false;
                this.DomainDataSource.GetDDSGroupDescriptorsCopy(this.ListOfDomainEntityFields, this.dataGridGroupItems);
                this.DomainDataSource.IsEnabled = true;
            }

            if (this.OnCancelButtonAfterClick != null)
            {
                changingGroupDescrs = true;
                try {
                  this.OnCancelButtonAfterClick(this, null);
                }
                finally {
                  changingGroupDescrs = false;
                }
            }

            if (this.DomainDataSource != null)
              RefreshControls(); // Apply-Clear-Cancel scenario, UI must be refreshed
        }

        public bool CanCancelFilters(object param)
        {
          if (this.DomainDataSource != null) {
            if (this.OnCanCancel != null) return OnCanCancel(this, null);
            else return this.DomainDataSource.GroupDescriptors.Count > 0;
          }
          else return false;
        }

        #endregion

        #endregion
    }
}
